package MyGui;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;
import java.awt.Window;
import java.util.*;
import java.text.NumberFormat;

import Element.*;
import DistSys.*;
/**
 * Title:        iPAD
 * Description:
 * Copyright:    Copyright (c) 2002
 * Company:      ABB Inc.
 * @author Fangxing Li
 * @version 1.0
 */
public class ElemListScrollPane extends JScrollPane {
    private MainFrame mainFrame;
    private JTable table;
    private ElemListTableModel model;
    /**
     * Vector of entries shown in the list. Each entry either be a
     * <code>AbsElem</code> or a class implementing the interface
     * <code>ElemListEntry</code>.
     */
    private Vector vElemList;

    ElemListScrollPane(MainFrame parent, int iPaneType){
        this(parent, iPaneType, JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
    }

    ElemListScrollPane(MainFrame parent, int iPaneType, int resizeMode){
        super();
        mainFrame = parent;
        vElemList = new Vector();
        model = new ElemListTableModel( vElemList, iPaneType );
        table = new JTable( model );
        table.setAutoResizeMode(resizeMode);
        table.setFont(GuiConst.fontDefault);
        table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        table.setShowGrid(false);
        for(int i=0; i< model.aiColumnWidth.length; i++){
            int width = model.aiColumnWidth[i];
            table.getColumnModel().getColumn(i).setPreferredWidth( width );
        }
        table.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent evt) {
                if (evt.getClickCount() == 2) {
                    gotoSelectedElem();
                }
            }
        });
        this.getViewport().setView(table);
    }

    public JTable getTable(){ return table; }
    public ElemListTableModel getModel() { return model; }
    public Vector getData() { return vElemList; }

    public void gotoSelectedElem( ){
        int cntr = table.getSelectedRowCount();
        if( cntr == 0) {
            JOptionPane.showMessageDialog(this, "No element selected." );
        } else if (cntr >= 2) {
            JOptionPane.showMessageDialog(this, "Please select only one." );
        } else {
            int index = table.getSelectedRow();
            if( index >= 0){
                Sys.clearSelectionAndFocus();
                Object objElem = vElemList.elementAt(index);
                if (objElem instanceof ElemListEntry) {
                    ((ElemListEntry)objElem).gotoElem(mainFrame.mainPanel);
                } else { // (objElem instanceof AbsElem)
                    AbsElem centerElem = (AbsElem)objElem;
                    Sys.addElemToSelection(centerElem);
                    Sys.focusElem = centerElem;
                    mainFrame.mainPanel.centerForElem(centerElem);
                    Window elemInfoDlg = mainFrame.menuBar.aIpadDlg[
                        mainFrame.menuBar.ELEM_INFO_DLG];
                    if( elemInfoDlg != null && elemInfoDlg.isVisible() ){
                        //Only one selected elem, i.e., focusElem
                        mainFrame.menuBar.showElemInfoForAnyCase();
                    }
                }
            }
        }
    }

    /**
     * Un-select all previous selected elements and then
     * put all elements in this table into Sys.selectedList.
     */
    public void selectAll(){
        Sys.clearSelectionAndFocus();
        int sz = vElemList.size();
        if (sz > 0) {
            for(int i=0;i<sz;i++){
                Object objElem = vElemList.elementAt(i);
                if (objElem instanceof ElemListEntry) {
                    ((ElemListEntry)objElem).addElemToSelection();
                } else { // (objElem instanceof AbsElem)
                    Sys.addElemToSelection((AbsElem)objElem);
                }
            }
            getTable().setRowSelectionInterval(0, sz-1);
        }
        mainFrame.mainPanel.setNeedRedraw( true );
        mainFrame.mainPanel.repaint();
    }

    /**
     * Highlights all selected entries in this table.
     */
    public void highLight(){
        Sys.highLightedElemList.removeAllElements();
        int[] aiSelection = table.getSelectedRows();
        for(int i=0; i<aiSelection.length; i++){
            Object objElem = vElemList.elementAt(aiSelection[i]);
            if (objElem instanceof ElemListEntry) {
                ((ElemListEntry)objElem).addElemToHighLightedElemList();
            } else { // (objElem instanceof AbsElem)
                Sys.highLightedElemList.add((AbsElem)objElem);
            }
        }
        mainFrame.mainPanel.setNeedRedraw( true );
        mainFrame.mainPanel.repaint();
    }

    /**
     * Removes all elements from the highlight list.
     */
    public void clearHighLights(){
        Sys.highLightedElemList.removeAllElements();
        mainFrame.mainPanel.setNeedRedraw( true );
        mainFrame.mainPanel.repaint();
    }

    /**
     * Un-select all previous selected elements and then
     * put all selected entries in this table into Sys.selectedList.
     */
    public void select(){
        Sys.clearSelectionAndFocus();
        addToSelection();
    }

    /**
     * Add selected entries into selectedList;
     * Previous selected elements will not be removed.
     */
    public void addToSelection(){
        int[] aiSelection = table.getSelectedRows();
        for(int i=0; i<aiSelection.length; i++){
            Object objElem = vElemList.elementAt(aiSelection[i]);
            if (objElem instanceof ElemListEntry) {
                ((ElemListEntry)objElem).addElemToSelection();
            } else { // (objElem instanceof AbsElem)
                Sys.addElemToSelection((AbsElem)objElem);
            }
        }
        mainFrame.mainPanel.setNeedRedraw( true );
        mainFrame.mainPanel.repaint();
    }

    public void updateTable(){
        Vector vTmp = new Vector(vElemList.size());
        int[] aiSelectedRows = new int[table.getSelectedRowCount()];
        int iSelectedRowCount = 0;
        for(int i=0; i<vElemList.size(); i++){
            Object objElem = vElemList.elementAt(i);
            boolean bAdd = false;
            if (objElem instanceof ElemListEntry) {
                bAdd = ((ElemListEntry)objElem).updateElem();
            } else { // (objElem instanceof AbsElem)
                bAdd = Sys.elemList.contains((AbsElem) objElem);
            }
            if (bAdd) {
                if (table.isRowSelected(i)) {
                    // if this row was selected remember the new index
                    aiSelectedRows[iSelectedRowCount] = vTmp.size();
                    iSelectedRowCount++;
                }
                vTmp.add(objElem);
            }
        }

        model.vElemList.removeAllElements( );
        model.vElemList.addAll( vTmp );
        model.fireTableDataChanged();

        // reselect all remaining previously selected rows
        for (int i = 0; i < iSelectedRowCount; i++)
            table.addRowSelectionInterval(aiSelectedRows[i], aiSelectedRows[i]);
    }
}//end of class ElemListScrollPane

class ElemListTableModel extends AbstractTableModel {
    final static int PANE_LOG     = 0;
    final static int PANE_FIND    = 1;
    final static int PANE_TROUBLE = 2;
    final static int PANE_QUERY   = 3;
    final static int PANE_TXPARA  = 4;
    //final static int PANE_DATASUM = 5;
    //final static int PANE_COSTSUM = 6;
    final static int NUM_PANE     = 5;

    //all possible columns which may appear as column titles
    final static String [] COLUMN_NAME = { "ID", "Name", "Description", "Type",
          "Template", "Message", "Score" };
    final static int[] COLUMN_WIDTH={ 40, 100, 150, 80, 150, 200, 50 };
    final static int  FIELD_ID         = 0;
    final static int  FIELD_NAME       = 1;
    final static int  FIELD_DESC       = 2;
    final static int  FIELD_TYPE       = 3;
    final static int  FIELD_TMPLT      = 4;
    final static int  FIELD_MSG        = 5;
    final static int  FIELD_SCORE      = 6;
    final static int  FIELD_SCORE_PERC = 7; // do not use this in ACTIVE_FIELD

    //Different PANEs need different colummns
    final static int[][] ACTIVE_FIELD;
    static{
        ACTIVE_FIELD = new int[NUM_PANE][];
        ACTIVE_FIELD[PANE_LOG]    = new int[]{ FIELD_ID, FIELD_NAME, FIELD_TYPE, FIELD_TMPLT, FIELD_MSG};
        ACTIVE_FIELD[PANE_FIND]   = new int[]{ FIELD_ID, FIELD_NAME, FIELD_TYPE, FIELD_DESC, FIELD_TMPLT};
        ACTIVE_FIELD[PANE_TROUBLE]= new int[]{ FIELD_ID, FIELD_NAME, FIELD_TYPE, FIELD_MSG};
        ACTIVE_FIELD[PANE_QUERY]  = new int[]{ FIELD_SCORE, FIELD_ID, FIELD_NAME};
        ACTIVE_FIELD[PANE_TXPARA] = new int[]{ FIELD_NAME, FIELD_DESC, FIELD_TMPLT, FIELD_TYPE};
    }

    String[]  asColumnName;
    int[]     aiColumnWidth;
    int       iPaneType;
    boolean   bIsQueryScoreInPercent=false;
    boolean   bIsQueryScoreInPUL=false;
    Vector    vElemList;

    static NumberFormat nf = null;

    public ElemListTableModel( Vector v, int iPaneType) {
        vElemList = v;
        this.iPaneType = iPaneType;
        int sz = ACTIVE_FIELD[iPaneType].length;
        asColumnName = new String[ sz ];
        aiColumnWidth= new int[ sz ];
        for(int i=0; i<sz; i++){
            int index = ACTIVE_FIELD[ iPaneType ] [i];
            asColumnName[i] = COLUMN_NAME[ index ];
            aiColumnWidth[i]= COLUMN_WIDTH[ index];
        }
    }

    public int getColumnCount() { return asColumnName.length; }
    public int getRowCount() { return vElemList.size(); }
    public String getColumnName(int col) { return asColumnName[col]; }
    public static Object getElemValue(AbsElem elem, int iField) {
        if (iField == FIELD_ID)
            return ""+(Sys.elemList.indexOf(elem)+1);
        else if (iField == FIELD_NAME)
            return elem.getElemGeomObj().getName();
        else if( iField == FIELD_DESC)
            return elem.getElemGeomObj().getDesc();
        else if( iField == FIELD_TYPE)
            return elem.getStringForType();
        else if( iField == FIELD_TMPLT)
            return elem.getDftTempName();
        else if( iField == FIELD_SCORE || iField == FIELD_SCORE_PERC) {
            if (nf == null) {
                int iNumDigits;
                if( iField == FIELD_SCORE){ iNumDigits = 4; }
                else { iNumDigits = 2; }
                nf = NumberFormat.getNumberInstance();
                nf.setMinimumFractionDigits( iNumDigits );
                nf.setMaximumFractionDigits( iNumDigits );
            }
            if( iField == FIELD_SCORE_PERC) {
                return nf.format(elem.getResult(AbsElem.RES_QUERY_SCORE_PERC))+"%";
            } else {
                return nf.format(elem.getResult(AbsElem.RES_QUERY_SCORE));
            }
        } else if( iField == FIELD_MSG ) {
            return elem.getMsgForLog();
        }
        return null;
    }
    public Object getValueAt(int row, int col) {
        int iField = ACTIVE_FIELD[iPaneType][col];
        if (iField == FIELD_SCORE && bIsQueryScoreInPercent)
            iField = FIELD_SCORE_PERC;

        Object objElem = vElemList.elementAt(row);
        if (objElem instanceof ElemListEntry)
            return ((ElemListEntry)objElem).getElemValue(iField);
        else // (objElem instanceof AbsElem)
            return getElemValue((AbsElem)objElem, iField);
    }

    public Class getColumnClass(int col) {
        int iField = ACTIVE_FIELD[iPaneType][col];
        if (iField == FIELD_ID ||
            iField == FIELD_SCORE || iField == FIELD_SCORE_PERC)
            return Number.class;
        else
            return String.class;
    }

    public void setIsQueryScoreInPercent(boolean bPercent) {
        bIsQueryScoreInPercent = bPercent;
    }

    public void updateQueryScoreInPerUnit(boolean bPUL) {
        if( this.bIsQueryScoreInPUL == bPUL) { return; }
        else { this.bIsQueryScoreInPUL = bPUL; }

        AbsElem elem;
        Object obj;
        double dNewScore;
        double dMaxScore = Double.NEGATIVE_INFINITY;
        for(int i=0; i<vElemList.size(); i++){
            obj = vElemList.get ( i );
            if( obj instanceof Line ) { //only applies to Line
                elem = (Line) obj;
                dNewScore = elem.getResult(AbsElem.RES_QUERY_SCORE);
                if( bPUL ){
                    dNewScore /= elem.getData( AbsElem.DATA_LENGTH);
                } else {
                    dNewScore *= elem.getData( AbsElem.DATA_LENGTH);
                }
                elem.setResult( AbsElem.RES_QUERY_SCORE, dNewScore);
                if( dNewScore > dMaxScore ) { dMaxScore = dNewScore; }
            } else{
                //error
            }
        }//end of for loop to find QueryScore

        //find Query Score in %
        if ( Math.abs( dMaxScore ) > 0) {
            double dScore;
            for(int i=0; i<vElemList.size(); i++){
                obj = vElemList.elementAt(i);
                if( obj instanceof AbsElem){ //for all elements
                    elem = (AbsElem) obj;
                    dScore = elem.getResult(AbsElem.RES_QUERY_SCORE);
                    dScore = dScore * 100.0 / dMaxScore ;
                    elem.setResult( AbsElem.RES_QUERY_SCORE_PERC, dScore );
                } else {
                    //error
                }
            }
        }

        TreeSet resultsInTree = new TreeSet( new QueryScoreComparator() );
        resultsInTree.addAll( vElemList );
        vElemList.removeAllElements();
        vElemList.addAll( resultsInTree);
    }//end of updateQueryScoreInPerUnit();
}//end of class ElemListTableModel

/**
 *  The <code>ElemListEntry</code> interface specifies the methods that will be
 *  used to select, highlight, update and display this list entry.
 */
interface ElemListEntry {
    /**
     * Selects this entry in the drawing panel and centers the drawing panel to
     * this entry.
     *
     * @param mainPanel  the drawing panel
     */
    public void gotoElem(DrawingPanel mainPanel);
    /**
     * Adds this entry to the selection (in the drawing panel).
     */
    public void addElemToSelection();
    /**
     * Adds this entry to the list of special highlighted elements
     * <code>Sys.highLightedElemList</code>.
     */
    public void addElemToHighLightedElemList();
    /**
     * Updates this entry.
     *
     * @return  true, if the entry should be kept in the list;
     *          false, if it should be removed.
     */
    public boolean updateElem();
    /**
     * Returns the value to display for the given field.
     *
     * @param iField  the number of the field the display object is searched for
     * @return  the object to be displayed
     */
    public Object getElemValue(int iField);
}

/**
 * The <code>ElemListAbsElemEntry</code> class is an implementaion of the
 * <code>ElemListEntry</code> interface that holds one <code>AbsElem</code>
 * object and performs the default actions.<p>
 * It can be used as a base class for further customized handling.
 */
class ElemListAbsElemEntry implements ElemListEntry {
    protected AbsElem elem = null;
    public ElemListAbsElemEntry(AbsElem e) { elem = e; }

    public void gotoElem(DrawingPanel mainPanel) {
        Sys.addElemToSelection(elem);
        Sys.focusElem = elem;
        mainPanel.centerForElem(elem);
    }

    public void addElemToSelection() {
        Sys.addElemToSelection(elem);
    }

    public void addElemToHighLightedElemList() {
        Sys.highLightedElemList.add(elem);
    }

    public boolean updateElem() {
        return Sys.elemList.contains(elem);
    }

    public Object getElemValue(int iField) {
        return ElemListTableModel.getElemValue(elem, iField);
    }
}

/**
 * The <code>ElemListVectorEntry</code> class is an implementaion of the
 * <code>ElemListEntry</code> interface that is in fact a <code>Vector</code>.
 * It performs the default actions transfered to a list of elements.<p>
 * It can also be used as a base class for further customized handling.
 */
class ElemListVectorEntry extends Vector implements ElemListEntry {
    public void gotoElem(DrawingPanel mainPanel) {
        AbsElem elem = null;
        for (int i = 0; i < size(); i++) {
            elem = (AbsElem)elementAt(i);
            Sys.addElemToSelection(elem);
        }
        // focus the last element
        Sys.focusElem = elem;
        mainPanel.centerForVector(this);
    }

    public void addElemToSelection() {
        for (int j = 0; j < size(); j++)
            Sys.addElemToSelection((AbsElem)elementAt(j));
    }

    public void addElemToHighLightedElemList() {
        Sys.highLightedElemList.addAll(this);
    }

    public boolean updateElem() {
        for (int j = 0; j < size(); j++) {
            if (!Sys.elemList.contains(elementAt(j)))
                removeElementAt(j);
        }
        return !isEmpty();
    }

    public Object getElemValue(int iField) {
        if (size() > 1) {
            if (iField == ElemListTableModel.FIELD_ID) {
                StringBuffer s = new StringBuffer();
                s.append(Sys.elemList.indexOf(elementAt(0))+1);
                for (int i = 1; i < size(); i++) {
                    s.append(", ");
                    s.append(Sys.elemList.indexOf(elementAt(i))+1);
                }
                return s.toString();
            } else if (iField == ElemListTableModel.FIELD_NAME ||
                       iField == ElemListTableModel.FIELD_DESC ||
                       iField == ElemListTableModel.FIELD_TYPE ||
                       iField == ElemListTableModel.FIELD_TMPLT ||
                       iField == ElemListTableModel.FIELD_SCORE ||
                       iField == ElemListTableModel.FIELD_SCORE_PERC) {
                return "Multiple Components";
            }
        } else if (size() == 1) {
            return ElemListTableModel.getElemValue((AbsElem)elementAt(0),
                iField);
        }
        return null;
    }
}
